From 12aa8e3d1c799c4f2de2ce03b2fe463cde920993 Mon Sep 17 00:00:00 2001 From: "awilliam@xenbuild.aw" Date: Fri, 10 Mar 2006 08:25:54 -0700 Subject: [PATCH] [IA64] domU destroy Signed-off-by: Akio Takebe Signed-off-by: Masaki Kanno --- xen/arch/ia64/xen/domain.c | 133 ++++++++++++++++++++++++++++--- xen/arch/ia64/xen/regionreg.c | 1 - xen/include/asm-ia64/domain.h | 2 + xen/include/asm-ia64/regionreg.h | 9 +++ 4 files changed, 135 insertions(+), 10 deletions(-) diff --git a/xen/arch/ia64/xen/domain.c b/xen/arch/ia64/xen/domain.c index 242919343c..2b0ca6024f 100644 --- a/xen/arch/ia64/xen/domain.c +++ b/xen/arch/ia64/xen/domain.c @@ -49,6 +49,8 @@ #include #include #include +#include +#include #define CONFIG_DOMAIN0_CONTIGUOUS unsigned long dom0_start = -1L; @@ -69,10 +71,7 @@ extern unsigned long dom_fw_setup(struct domain *, char *, int); /* FIXME: where these declarations should be there ? */ extern void domain_pend_keyboard_interrupt(int); extern long platform_is_hp_ski(void); -extern unsigned long allocate_metaphysical_rr(void); -extern int allocate_rid_range(struct domain *, unsigned long); extern void sync_split_caches(void); -extern void init_all_rr(struct vcpu *); extern void serial_input_init(void); static void init_switch_stack(struct vcpu *v); @@ -80,9 +79,33 @@ static void init_switch_stack(struct vcpu *v); /* this belongs in include/asm, but there doesn't seem to be a suitable place */ void arch_domain_destroy(struct domain *d) { - printf("arch_domain_destroy: not implemented\n"); - //free_page((unsigned long)d->mm.perdomain_pt); - free_xenheap_page(d->shared_info); + struct page *page; + struct list_head *ent, *prev; + + if (d->arch.mm->pgd != NULL) + { + list_for_each ( ent, &d->arch.mm->pt_list ) + { + page = list_entry(ent, struct page, list); + prev = ent->prev; + list_del(ent); + free_xenheap_page(page_to_virt(page)); + ent = prev; + } + pgd_free(d->arch.mm->pgd); + } + if (d->arch.mm != NULL) + xfree(d->arch.mm); + if (d->shared_info != NULL) + free_xenheap_page(d->shared_info); + + deallocate_rid_range(d); + + /* It is really good in this? */ + flush_tlb_all(); + + /* It is really good in this? */ + vhpt_flush(); } static void default_idle(void) @@ -187,6 +210,8 @@ struct vcpu *alloc_vcpu_struct(struct domain *d, unsigned int vcpu_id) void free_vcpu_struct(struct vcpu *v) { + if (v->arch.privregs != NULL) + free_xenheap_pages(v->arch.privregs, get_order(sizeof(mapped_regs_t))); free_xenheap_pages(v, KERNEL_STACK_SIZE_ORDER); } @@ -239,6 +264,7 @@ int arch_domain_create(struct domain *d) if ((d->arch.mm = xmalloc(struct mm_struct)) == NULL) goto fail_nomem; memset(d->arch.mm, 0, sizeof(*d->arch.mm)); + INIT_LIST_HEAD(&d->arch.mm->pt_list); if ((d->arch.mm->pgd = pgd_alloc(d->arch.mm)) == NULL) goto fail_nomem; @@ -310,10 +336,74 @@ int arch_set_info_guest(struct vcpu *v, struct vcpu_guest_context *c) return 0; } +static void relinquish_memory(struct domain *d, struct list_head *list) +{ + struct list_head *ent; + struct page *page; +#ifndef __ia64__ + unsigned long x, y; +#endif + + /* Use a recursive lock, as we may enter 'free_domheap_page'. */ + spin_lock_recursive(&d->page_alloc_lock); + ent = list->next; + while ( ent != list ) + { + page = list_entry(ent, struct page, list); + /* Grab a reference to the page so it won't disappear from under us. */ + if ( unlikely(!get_page(page, d)) ) + { + /* Couldn't get a reference -- someone is freeing this page. */ + ent = ent->next; + continue; + } + + if ( test_and_clear_bit(_PGT_pinned, &page->u.inuse.type_info) ) + put_page_and_type(page); + + if ( test_and_clear_bit(_PGC_allocated, &page->count_info) ) + put_page(page); + +#ifndef __ia64__ + /* + * Forcibly invalidate base page tables at this point to break circular + * 'linear page table' references. This is okay because MMU structures + * are not shared across domains and this domain is now dead. Thus base + * tables are not in use so a non-zero count means circular reference. + */ + y = page->u.inuse.type_info; + for ( ; ; ) + { + x = y; + if ( likely((x & (PGT_type_mask|PGT_validated)) != + (PGT_base_page_table|PGT_validated)) ) + break; + + y = cmpxchg(&page->u.inuse.type_info, x, x & ~PGT_validated); + if ( likely(y == x) ) + { + free_page_type(page, PGT_base_page_table); + break; + } + } +#endif + + /* Follow the list chain and /then/ potentially free the page. */ + ent = ent->next; + put_page(page); + } + + spin_unlock_recursive(&d->page_alloc_lock); +} + void domain_relinquish_resources(struct domain *d) { - /* FIXME */ - printf("domain_relinquish_resources: not implemented\n"); + /* Relinquish every page of memory. */ + + /* xenheap_list is not used in ia64. */ + BUG_ON(!list_empty(&d->xenpage_list)); + + relinquish_memory(d, &d->page_list); } // heavily leveraged from linux/arch/ia64/kernel/process.c:copy_thread() @@ -389,7 +479,7 @@ static struct page * assign_new_domain0_page(unsigned long mpaddr) struct page * assign_new_domain_page(struct domain *d, unsigned long mpaddr) { struct mm_struct *mm = d->arch.mm; - struct page *p = (struct page *)0; + struct page *pt, *p = (struct page *)0; pgd_t *pgd; pud_t *pud; pmd_t *pmd; @@ -401,16 +491,28 @@ struct page * assign_new_domain_page(struct domain *d, unsigned long mpaddr) } pgd = pgd_offset(mm,mpaddr); if (pgd_none(*pgd)) + { pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pgd_val(*pgd)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pud = pud_offset(pgd, mpaddr); if (pud_none(*pud)) + { pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pud_val(*pud)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pmd = pmd_offset(pud, mpaddr); if (pmd_none(*pmd)) + { pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); // pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pmd_val(*pmd)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pte = pte_offset_map(pmd, mpaddr); if (pte_none(*pte)) { @@ -443,6 +545,7 @@ struct page * assign_new_domain_page(struct domain *d, unsigned long mpaddr) void assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long physaddr) { struct mm_struct *mm = d->arch.mm; + struct page *pt; pgd_t *pgd; pud_t *pud; pmd_t *pmd; @@ -454,16 +557,28 @@ void assign_domain_page(struct domain *d, unsigned long mpaddr, unsigned long ph } pgd = pgd_offset(mm,mpaddr); if (pgd_none(*pgd)) + { pgd_populate(mm, pgd, pud_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pgd_val(*pgd)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pud = pud_offset(pgd, mpaddr); if (pud_none(*pud)) + { pud_populate(mm, pud, pmd_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pud_val(*pud)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pmd = pmd_offset(pud, mpaddr); if (pmd_none(*pmd)) + { pmd_populate_kernel(mm, pmd, pte_alloc_one_kernel(mm,mpaddr)); // pmd_populate(mm, pmd, pte_alloc_one(mm,mpaddr)); + pt = maddr_to_page(pmd_val(*pmd)); + list_add_tail(&pt->list, &d->arch.mm->pt_list); + } pte = pte_offset_map(pmd, mpaddr); if (pte_none(*pte)) { diff --git a/xen/arch/ia64/xen/regionreg.c b/xen/arch/ia64/xen/regionreg.c index 96b3094797..8718b931a1 100644 --- a/xen/arch/ia64/xen/regionreg.c +++ b/xen/arch/ia64/xen/regionreg.c @@ -157,7 +157,6 @@ int deallocate_rid_range(struct domain *d) int rid_block_end = d->arch.ending_rid >> IA64_MIN_IMPL_RID_BITS; int rid_block_start = d->arch.starting_rid >> IA64_MIN_IMPL_RID_BITS; - return 1; // KLUDGE ALERT // // not all domains will have allocated RIDs (physical mode loaders for instance) // diff --git a/xen/include/asm-ia64/domain.h b/xen/include/asm-ia64/domain.h index 92f1a210c3..4ac050da1a 100644 --- a/xen/include/asm-ia64/domain.h +++ b/xen/include/asm-ia64/domain.h @@ -102,6 +102,8 @@ struct mm_struct { #endif spinlock_t page_table_lock; /* Protects task page tables and mm->rss */ + struct list_head pt_list; /* List of pagetable */ + struct list_head mmlist; /* List of all active mm's. These are globally strung * together off init_mm.mmlist, and are protected * by mmlist_lock diff --git a/xen/include/asm-ia64/regionreg.h b/xen/include/asm-ia64/regionreg.h index ed35dcff35..cd4077b301 100644 --- a/xen/include/asm-ia64/regionreg.h +++ b/xen/include/asm-ia64/regionreg.h @@ -64,4 +64,13 @@ vmMangleRID(unsigned long RIDVal) // since vmMangleRID is symmetric, use it for unmangling also #define vmUnmangleRID(x) vmMangleRID(x) +extern unsigned long allocate_metaphysical_rr(void); + +struct domain; +extern int allocate_rid_range(struct domain *d, unsigned long ridbits); +extern int deallocate_rid_range(struct domain *d); + +struct vcpu; +extern void init_all_rr(struct vcpu *v); + #endif /* !_REGIONREG_H_ */ -- 2.30.2